﻿using System;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement.Drivers;
using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Roles.Models;
using Orchard.Roles.Services;
using Orchard.Roles.ViewModels;
using Orchard.Security;
using Orchard.UI.Notify;
using Orchard.Environment.Extensions;
using Rework.CommerceHistory.Models;
using Rework.CommerceHistory.ViewModels;
using Nwazet.Commerce.Models;
using System.Collections.Generic;
using System.Web.Mvc;

namespace Rework.CommerceHistory.Drivers {
    [OrchardFeature("Rework.CommerceRoleAssignment")]
    [UsedImplicitly]
    public class CommerceRoleAssignmentPartDriver : ContentPartDriver<CommerceRoleAssignmentPart> {
        private readonly IRepository<CommerceProductRolesRecord> _productRolesRepository;
        private readonly IRoleService _roleService;
        private readonly INotifier _notifier;
        private readonly IAuthenticationService _authenticationService;
        private readonly IAuthorizationService _authorizationService;
        private const string TemplateName = "Parts/Commerce.ProductRoles";

        public CommerceRoleAssignmentPartDriver(
            IRepository<CommerceProductRolesRecord> productRolesRepository, 
            IRoleService roleService, 
            INotifier notifier,
            IAuthenticationService authenticationService,
            IAuthorizationService authorizationService) {
            _productRolesRepository = productRolesRepository;
            _roleService = roleService;
            _notifier = notifier;
            _authenticationService = authenticationService;
            _authorizationService = authorizationService;
            T = NullLocalizer.Instance;
        }

        protected override string Prefix {
            get {
                return "ProductRoles";
            }
        }

        public Localizer T { get; set; }

        protected override DriverResult Editor(CommerceRoleAssignmentPart commerceRoleAssignmentPart, dynamic shapeHelper) {
            // don't show editor without apply roles permission
            if (!_authorizationService.TryCheckAccess(StandardPermissions.SiteOwner, _authenticationService.GetAuthenticatedUser(), commerceRoleAssignmentPart))
                return null;

            return ContentShape("Parts_Commerce_ProductRoles_Edit",
                    () => {
                       var roles =_roleService.GetRoles().Select(x => new ProductRoleEntry {
                                                                          RoleId = x.Id,
                                                                          Name = x.Name,
                                                                          Granted = commerceRoleAssignmentPart.Roles.Contains(x.Name)});
                       var model = new ProductRolesViewModel {
                           ProductId = commerceRoleAssignmentPart.ContentItem.Id,
                           Roles = roles.ToList(),
                           NumberOfPeriods = commerceRoleAssignmentPart.NumberOfPeriods,
                           PeriodType = commerceRoleAssignmentPart.PeriodType,
                           PeriodTypes = GetPeriodTypes(commerceRoleAssignmentPart.PeriodType)
                       };
                       return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix);
                    });
        }

        protected override DriverResult Editor(CommerceRoleAssignmentPart commerceRoleAssignmentPart, IUpdateModel updater, dynamic shapeHelper) {
            // don't apply editor without apply roles permission
            if (!_authorizationService.TryCheckAccess(StandardPermissions.SiteOwner, _authenticationService.GetAuthenticatedUser(), commerceRoleAssignmentPart))
                return null;

            var viewModel = new ProductRolesViewModel();
            viewModel.ProductId = commerceRoleAssignmentPart.Id;
            viewModel.PeriodTypes = GetPeriodTypes(viewModel.PeriodType);

            if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
                var currentProductRoleRecords = _productRolesRepository.Fetch(x => x.ProductId == viewModel.ProductId);
                var currentRoleRecords = currentProductRoleRecords.Select(x => x.Role);
                var targetRoleRecords = viewModel.Roles.Where(x => x.Granted).Select(x => _roleService.GetRole(x.RoleId));
                foreach (var addingRole in targetRoleRecords.Where(x => !currentRoleRecords.Contains(x))) {
                    _notifier.Warning(T("Adding role {0} to product {1}", addingRole.Name, viewModel.ProductId));
                    _productRolesRepository.Create(new CommerceProductRolesRecord { ProductId = viewModel.ProductId, Role = addingRole });
                }
                foreach (var removingRole in currentProductRoleRecords.Where(x => !targetRoleRecords.Contains(x.Role))) {
                    _notifier.Warning(T("Removing role {0} from product {1}", removingRole.Role.Name, viewModel.ProductId));
                    _productRolesRepository.Delete(removingRole);
                }

                commerceRoleAssignmentPart.NumberOfPeriods = viewModel.NumberOfPeriods;
                commerceRoleAssignmentPart.PeriodType = viewModel.PeriodType;
            }
            return ContentShape("Parts_Commerce_ProductRoles_Edit",
                                () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: viewModel, Prefix: Prefix));
        }
        
        private static IEnumerable<SelectListItem> GetPeriodTypes(PeriodOptions periodType) {
            IEnumerable<SelectListItem> periodTypes;

            periodTypes = Enum.GetValues(typeof(PeriodOptions)).Cast<PeriodOptions>()
                .Select(val => new SelectListItem {
                    Value = val.ToString(),
                    Text = val.ToString(),
                    Selected = val == periodType,
                });

            return periodTypes;
        }

        //protected override void Importing(UserRolesPart part, ContentManagement.Handlers.ImportContentContext context) {
        //    var roles = context.Attribute(part.PartDefinition.Name, "Roles");
        //    if(string.IsNullOrEmpty(roles)) {
        //        return;
        //    }

        //    var userRoles = roles.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);

        //    // create new roles
        //    foreach (var role in userRoles) {
        //        var roleRecord = _roleService.GetRoleByName(role);

        //        // create the role if it doesn't already exist
        //        if (roleRecord == null) {
        //            _roleService.CreateRole(role);
        //        }
        //    }

        //    var currentUserRoleRecords = _productRolesRepository.Fetch(x => x.UserId == part.ContentItem.Id).ToList();
        //    var currentRoleRecords = currentUserRoleRecords.Select(x => x.Role).ToList();
        //    var targetRoleRecords = userRoles.Select(x => _roleService.GetRoleByName(x)).ToList();
        //    foreach (var addingRole in targetRoleRecords.Where(x => !currentRoleRecords.Contains(x))) {
        //        _productRolesRepository.Create(new UserRolesPartRecord { UserId = part.ContentItem.Id, Role = addingRole });
        //    }
        //}

        //protected override void Exporting(UserRolesPart part, ContentManagement.Handlers.ExportContentContext context) {
        //    context.Element(part.PartDefinition.Name).SetAttributeValue("Roles", string.Join(",", part.Roles));
        //}
    }
}